/*
    Copyright 2008, 2009, 2010 Brightworks, Inc.

    This file is part of Language Mentor.

    Language Mentor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Language Mentor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Language Mentor.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.langcollab.languagementor.controller.audio
{
    import com.brightworks.util.Debug;

    import flash.events.Event;

    public class AudioSequenceBranch extends AudioSequenceElement
    {
        public var autoAdvance:Boolean = true;
        public var elements:Object;

        public function get currentElementIndex():int
        {
            // We're actually looking for the index of _currentElement within the sequence defined by _sequenceStrategy.
            // So if our elements prop has props named "a", "b", "C", ... "z", and our sequence strategy is defining
            // our sequence as "g", "b", "h", and _currentElement references the value associated with "b", this
            // method should return the integer 1.
            var result:int = _sequenceStrategy.currentOrderSpecListIndex;
            if (result < 0) 
                Debug.error_Fatal("AudioSequenceBranch.currentElementIndex(): no current element");
            return result;
        }

        private var _currentElement:AudioSequenceElement;
        private var _sequenceStrategy:ISequenceStrategy;

        public function AudioSequenceBranch()
        {
            super();
            isLeaf = false;
        }

        // ****************************************************
        //
        //          Public Methods
        //
        // ****************************************************

        public override function dispose():void
        {
            elements = null;
            _sequenceStrategy.dispose();
            _sequenceStrategy = null;
            removeEventListeners();
            for (var propName:String in elements)
            {
                AudioSequenceElement(elements[propName]).dispose();
                elements[propName] = null;
            }
        }

        public function moveToElement(levelId:String, id:Object):void
        {
            if (levelId == this.levelId)
            {
                if (!_sequenceStrategy.isElementAllowed(id))
                {
                    _sequenceStrategy.isElementAllowed(id); // for debugging
                    Debug.error_Fatal(["AudioSequenceBranch.moveToElement(): passed element id not approved by sequence strategy:", id]);
                }
                var newElement:AudioSequenceElement = _sequenceStrategy.getElement(id);
                if (newElement != _currentElement)
                {
                    cleanupCurrentElement();
                    startElement(newElement);
                }
            }
            else
            {
                if (_currentElement.isLeaf) 
                    Debug.error_Fatal(["AudioSequenceBranch.moveToElement(): passed levelId doesn't match, and current element is a leaf:", levelId]);
                AudioSequenceBranch(_currentElement).moveToElement(levelId, id);
            }
        }

        public override function pause(levelIdForLevelToRestartFromBeginning:String):void
        {
            super.pause(levelIdForLevelToRestartFromBeginning);
            if (!_currentElement) 
                Debug.error_Fatal("AudioSequenceBranch.resume(): no _currentElement");
            if (levelIdForLevelToRestartFromBeginning == this.levelId)
            {
                // We don't call stop() here because it sets isPlaying to false, but otherwise
                // we pretty much duplicate its code here.
                cleanupCurrentElement();
                _sequenceStrategy.reset();
            }
            else
            {
                _currentElement.pause(levelIdForLevelToRestartFromBeginning);
            }
        }

        public function replayCurrentElement(levelId:String):void
        {
            if (!_currentElement) 
                Debug.error_Fatal("AudioSequenceBranch.replayCurrentElement(): no _currentElement");
            if (levelId == this.levelId)
            {
                startElement(_currentElement);
            }
            else
            {
                if (!_currentElement is AudioSequenceBranch)
                    Debug.error_Fatal("AudioSequenceBranch.replayCurrentElement(): this.levelId doesn't match passed levelId, and _currentElement isn't branch");
                AudioSequenceBranch(_currentElement).replayCurrentElement(levelId);
            }
        }

        public override function resume(levelIdForLevelToRestartFromBeginning:String):void
        {
            super.resume(levelIdForLevelToRestartFromBeginning);
            if (levelIdForLevelToRestartFromBeginning == this.levelId)
            {
                startElement(_sequenceStrategy.getFirstElement());
            }
            else
            {
                if (!_currentElement) 
                    Debug.error_Fatal("AudioSequenceBranch.resume(): no _currentElement");
                _currentElement.resume(levelIdForLevelToRestartFromBeginning);
            }
        }

        public function setSequenceStrategy(strategy:ISequenceStrategy, levelId:String):void
        {
            if (this.levelId == levelId)
            {
                _sequenceStrategy = strategy;
                _sequenceStrategy.init(this.elements);
            }
            else
            {
                // call setSequenceStrategy() for all children
                for each (var element:AudioSequenceElement in elements)
                {
                    if (!element.isLeaf)
                    {
                        AudioSequenceBranch(element).setSequenceStrategy(strategy.clone(), levelId);
                    }
                }
            }
        }

        public override function start():void
        {
            //trace("AudioSeqenceBranch.start(): " + levelId + " " + id);
            super.start();
            AudioRecorder.getInstance().clear();
            if (_currentElement) 
                Debug.error_Fatal(["AudioSequenceBranch.start(): _currentElement is already an instance:", _currentElement]);
            startElement(_sequenceStrategy.getFirstElement());
        }

        public override function stop():void
        {
            super.stop();
            // We may not have a current element - see the pause() method for details
            if (_currentElement)
            {
                cleanupCurrentElement();
            }
            _sequenceStrategy.reset();
        }

        // ****************************************************
        //
        //          Protected Methods
        //
        // ****************************************************

        protected override function onElementComplete(event:Event):void
        {
            var element:AudioSequenceElement;
            cleanupCurrentElement();
            if (autoAdvance)
            {
                if (_sequenceStrategy.hasNextElement())
                {
                    element = _sequenceStrategy.getNextElement();
                    startElement(element);
                }
                else
                {
                    onAllElementsComplete();
                }
            }
            else
            {
                element = _sequenceStrategy.getCurrentElement();
                startElement(element);
            }
        }

        // ****************************************************
        //
        //          Private Methods
        //
        // ****************************************************

        private function cleanupCurrentElement():void
        {
            if (_currentElement.isPlaying)
            {
                _currentElement.stop();
            }
            removeEventListeners();
            _currentElement = null;
        }

        private function removeEventListeners():void
        {
            if (_currentElement)
            {
                _currentElement.removeEventListener(Event.COMPLETE, onElementComplete);
            }
        }

        private function startElement(element:AudioSequenceElement):void
        {
            _currentElement = element;
            _currentElement.addEventListener(Event.COMPLETE, onElementComplete);
            element.start();
        }
    }
}

